package thingapi

import (
	"iot-base/common/crudextend"
	"iot-base/common/dbconn"
	"iot-base/common/dbobj"
	"iot-base/common/webapi"
	"time"

	"github.com/gin-contrib/gzip"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"gorm.io/datatypes"
)

func init() {

}

//JSONBody 字段
type JSONBody struct {
	Identifier string
	Body       datatypes.JSON `json:"body"`
}

func getID(obj interface{}) string {
	ider, ok := obj.(dbconn.DBObjIDer)
	if ok {
		id := ider.GetID()
		ids, ok := id.(string)
		if ok {
			return ids
		}
	}
	return ""
}

type thingExtend struct {
	dbobj.Thing
	Params []dbobj.ThingParam `json:"params"`
}

func autoSetProxy(c *gin.Context) bool {
	var thing thingExtend
	if err := c.ShouldBindBodyWith(&thing, binding.JSON); err != nil {
		webapi.SendError("thing "+err.Error(), webapi.ParamMissed, c)
		return true
	}
	var model dbobj.TModel
	model.UID = thing.ModelID
	errdb := dbconn.DBConnection.First(&model).Error
	if errdb != nil {
		webapi.SendError(errdb.Error(), webapi.DBError, c)
		return true
	}
	if model.IsEdgeControl {
		thing.IsProxy = true
	}
	method := c.Request.Method
	msg := crudextend.CrudMsg{
		Action:       method,
		TModelID:     model.UID,
		PThing:       &thing.Thing,
		PThingParams: &thing.Params,
	}
	result := crudextend.GetExtendResult(model.UID, &msg)
	if result != nil {
		if result.Err != nil {
			webapi.SendError(result.Err.Error(), webapi.DBError, c)
			return true
		}
		if result.PThing != nil {
			thing.Thing = *result.PThing
		}
		if result.PThingParams != nil {
			thing.Params = *result.PThingParams
		}
	}

	if method == "POST" {
		errdb = dbconn.NewItem(&thing.Thing)
	} else {
		old := dbobj.Thing{
			UID: thing.Thing.UID,
		}
		derr := dbconn.DBConnection.First(&old).Error
		if derr == nil {
			timenow := time.Now()
			minfo := dbobj.ThingMaintainInfo{
				ThingID: thing.Thing.UID,
				//UsedTime: &timenow,
			}
			derr = dbconn.DBConnection.First(&minfo).Error
			if thing.Thing.StatusUsed != 1 {
				minfo.UsedTime = nil
				dbconn.DBConnection.Save(&minfo)
			} else if old.StatusUsed != thing.Thing.StatusUsed && thing.Thing.StatusUsed == 1 {
				minfo.UsedTime = &timenow
				if derr == nil {
					dbconn.DBConnection.Save(&minfo)
				} else {
					dbconn.DBConnection.Create(&minfo)
				}
			}
		}
		errdb = dbconn.Update(&thing.Thing)
	}
	if errdb != nil {
		webapi.SendError(errdb.Error(), webapi.DBError, c)
		//return true
	} else {
		webapi.SendResult(&thing, nil, c)
	}
	return true
}

func getThingEx() ([]map[string]interface{}, error) {
	var things []map[string]interface{}

	err := dbconn.DBConnection.Model(&dbobj.Thing{}).Select(`things.*,thing_stations.sno,thing_stations.station_id,
	stations.parent_id,thing_states.state`).
		Joins("left JOIN thing_stations ON thing_stations.thing_id = things.uid").
		Joins("left JOIN stations ON things.uid = stations.uid").
		Joins("left JOIN thing_states ON things.uid=thing_states.thing_id").
		Order("things.uid").
		Find(&things).Error
	return things, err
}

//InitThing 初始化模模型界面
func InitThing(author gin.HandlerFunc) (*gin.Engine, *gin.RouterGroup, *gin.RouterGroup) {
	r := gin.Default()
	r.Use(gzip.Gzip(gzip.DefaultCompression))
	r.Use(webapi.Cors())

	api := r.Group("/api")
	api.Use(author)
	initAlarm(api)
	initThingQueryAPI(api)
	initQueryAPI(api)

	cfg := api.Group("/cfg")
	{
		cfg.GET("/thingex", func(c *gin.Context) {
			res, err := getThingEx()
			webapi.SendResult(res, err, c)
		})
		initAreaAPI(cfg)
		funMap := make(map[string]func(c *gin.Context) bool)
		funMap["GETBYID"] = getQueryProperty
		funMap["PUT"] = saveModel
		funMap["POST"] = saveModel
		webapi.BindCrudEx(cfg, "/tmodel/", &dbobj.TModel{}, funMap, nil)
		/*thingFunAfterMap := make(map[string]func(obj interface{}, c *gin.Context) bool)
		thingFunAfterMap["DELETE"] = func(obj interface{}, c *gin.Context) bool {
			id, ok := obj.(string)
			if ok {
				DirtyThing(id)
			}
			return true
		}
		thingFunAfterMap["UPDATE"] = func(obj interface{}, c *gin.Context) bool {
			id := getID(obj)
			if id != "" {
				DirtyThing(id)
			}
			return true
		}
		thingFunAfterMap["POST"] = func(obj interface{}, c *gin.Context) bool {
			id := getID(obj)
			if id != "" {
				DirtyThing(id)
			}
			return true
		}*/
		funThingMap := make(map[string]func(c *gin.Context) bool)
		funThingMap["PUT"] = autoSetProxy
		funThingMap["POST"] = autoSetProxy

		webapi.BindCrudEx(cfg, "/thing/", &dbobj.Thing{}, funThingMap, nil)
		webapi.BindCrud(cfg, "/catalog/", &dbobj.Catalog{})
		//webapi.BindCrud(cfg, "/business/", &dbobj.Business{})
		funMap2 := make(map[string]func(c *gin.Context) bool)

		funMap2["PUT"] = func(c *gin.Context) bool {
			return updateStation(c, "PUT")
		}

		funMap2["POST"] = func(c *gin.Context) bool {
			return updateStation(c, "POST")
		}
		funMap2["GETBYID"] = getStationInfo
		funMap2["GETALL"] = getStationInfo
		funMap2["DELETE"] = func(c *gin.Context) bool {
			id := c.Param("id")
			err := beforeRemoveStation(id)
			if err != nil {
				webapi.SendError(err.Error(), webapi.DBError, c)

			} else {
				webapi.SendResult(nil, nil, c)
			}

			return true
		}
		webapi.BindCrudEx(cfg, "/station/", &dbobj.Station{}, funMap2, nil)
		//funMap2 := make(map[string]func(c *gin.Context) bool)
		webapi.BindCrud(cfg, "/area/", &dbobj.Area{})

		funMapTS := make(map[string]func(c *gin.Context) bool)
		funMapTS["PUT"] = saveTS
		funMapTS["POST"] = saveTS

		webapi.BindCrudEx(cfg, "/thingstation/", &dbobj.ThingStation{}, funMapTS, nil)

		funMapParam := make(map[string]func(c *gin.Context) bool)
		funMapParam["PUT"] = updateThingParamRest
		funMapParam["POST"] = updateThingParamRest
		funMapParam["GETBYID"] = queryThingParamRest
		funMapParam["DELETE"] = deleteThingParamRest
		webapi.BindCrudEx(cfg, "/thingparam/", &dbobj.ThingParam{}, funMapParam, nil)
		funMapProtocol := make(map[string]func(c *gin.Context) bool)
		funMapProtocol["GETBYID"] = queryTModelProtocolRest
		funMapProtocol["PUT"] = updateOneProtocol
		funMapProtocol["POST"] = updateProtocol
		funMapProtocol["DELETE"] = removeProtocol

		webapi.BindCrudEx(cfg, "/tmodelprotocol/", &dbobj.TModelProtocol{}, funMapProtocol, nil)
		initThingEditAPI(cfg)

	}

	return r, api, cfg
	//r.Run(":18866")

}
